/**
 * 
 */
package com.zte.claa.inficombo.csa.app.service.sapi.ffhost;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.zte.claa.inficombo.csa.app.dao.mysql.impl.FFResDataMapper;
import com.zte.claa.inficombo.csa.app.model.redis.AlarmData;
import com.zte.claa.inficombo.csa.app.service.csa.impl.BaseCacheManager;
import com.zte.claa.inficombo.csa.app.service.rptparse.ParserContainer;
import com.zte.claa.inficombo.csa.app.service.sapi.ffhost.bean.FFHostEvent;
import com.zte.claa.inficombo.csa.app.service.sapi.ffhost.bean.FFHostOpData;
import com.zte.claa.inficombo.csa.app.service.sapi.ffhost.bean.FFHostPartEvent;
import com.zte.claa.inficombo.csa.app.service.sapi.ffhost.bean.FFHostPartState;
import com.zte.claa.inficombo.csa.app.service.sapi.ffhost.bean.FFHostPartValue;
import com.zte.claa.inficombo.csa.app.service.sapi.ffhost.bean.FFHostState;
import com.zte.claa.inficombo.csa.app.service.sapi.ffhost.bean.FFResDevBase;
import com.zte.claa.inficombo.csa.app.service.sapi.ffhost.bean.FFTransDevEvent;
import com.zte.claa.inficombo.csa.app.service.sapi.ffhost.bean.FFTransDevOpData;
import com.zte.claa.inficombo.csa.app.service.sapi.ffhost.bean.FFTransDevState;
import com.zte.claa.inficombo.csa.app.util.JsonUtils;

/**
 * @author 0283000115
 *
 */

@Service("FFDataPeristentService")
public class FFDataPeristentService {
	// 日志.
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
	private FFResDataMapper resdataMapper;
	
	@Autowired
	private BaseCacheManager cacheManager;
	
	@Autowired
	private ParserContainer container;
	
	/**
	 * 保存上报数据，并根据状态上报标记产生告警或告警恢复消息. 
	 * 
	 * @param transdevEui
	 * @param dataflag
	 * @param metedataObj
	 * @throws Exception
	 */
	public void saveFFResDevRptData(String transdevEui, int dataflag, Object metedataObj) throws Exception {
		if(metedataObj == null){
			logger.warn("saveFFResDevRptData: data is null!");
			return;
		}
		this.saveJsonData(transdevEui, dataflag, String.valueOf(metedataObj));
	}
	
	/**
	 * 保存上报数据，并根据状态上报标记产生告警或告警恢复消息. 
	 * 
	 * @param transdevEui
	 * @param dataflag
	 * @param metedataObj
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public void saveFFResDevRptDataByBatch(String transdevEui, int dataflag, Object metedataList) throws Exception {
		List<String> jsonDataList = (List<String>)metedataList;
		for(String metedatajson : jsonDataList){
			this.saveJsonData(transdevEui, dataflag, metedatajson);
		}	
	}
	
	// 解析单条数据.
	private void saveJsonData(String transdevEui, int dataflag, String metedatajson) throws Exception {
		logger.info("Begin to save data: transdev={}, dataflag={}, data={}.", transdevEui, dataflag, metedatajson);
		FFResDevBase transDev = this.cacheManager.getFFTransDevByEui(transdevEui);
		if(transDev == null){
			logger.warn("FFTransdev not exist: "+transdevEui);
			return;
		}		
		switch(dataflag){
		case FFTransDevRptParseResult.DATAFLAG_FFSYS_STATE:			
			processFFHostStateData(transDev, metedatajson);			
			break;
		case FFTransDevRptParseResult.DATAFLAG_FFPART_STATE:
			processFFHostPartStateData(transDev, metedatajson);		
			break;
		case FFTransDevRptParseResult.DATAFLAG_FFPART_FIELDVALUE:
			processFFHostPartFieldValueData(transDev, metedatajson);	
			break;
		case FFTransDevRptParseResult.DATAFLAG_FFSYS_OPDATA:
			processFFHostOpLogData(transDev, metedatajson);	
			break;
		case FFTransDevRptParseResult.DATAFLAG_FFTRANSDEV_STATE:
			processFFTransdevStateData(transDev, metedatajson);		
			break;
		case FFTransDevRptParseResult.DATAFLAG_FFTRANSDEV_OPDATA:
			processFFTransdevOpLogData(transDev, metedatajson);		
			break;
		default:
			logger.info("Not support dataflag: {}, transdev: {}, data: {}", dataflag, transdevEui, metedatajson);
			break;
		}
	}
	
	/**
	 * 消防主机状态数据上报处理
	 * 
	 * @param transdevEui
	 * @param metedatajson
	 * @throws Exception
	 */
	private void processFFHostStateData(FFResDevBase transDev, String metedatajson) throws Exception {
		// 1.转换json对象.
		String transDevAddr = transDev.getTransdevaddr();		
		FFHostState ffHostState = JsonUtils.readValue(metedatajson, FFHostState.class);
		FFResDevBase hostDev = this.cacheManager.getFFHostDevByAddr(transDevAddr, ffHostState.getSysaddr());
		if(hostDev == null){
			logger.error("FFHostDev not exists: transDevAddr={}, sysaddr={}", transDevAddr, ffHostState.getSysaddr());
			return;
		}
		// 2.补充projectid和deveui等信息.
		ffHostState.setProjectid(hostDev.getProjectid());
		ffHostState.setDeveui(hostDev.getDeveui());
		Timestamp ts = ffHostState.getCollecttime();
		if(ts == null){
			ts = new Timestamp(System.currentTimeMillis());
			ffHostState.setCollecttime(ts);
		}
		// 3.持久化数据.
		// 3.1插入总体数据表（消防报表和统计分析用）；
		List<FFHostState> datas = new ArrayList<FFHostState>();
		datas.add(ffHostState);
		this.resdataMapper.addFFHostStateData(datas);
		// 3.2解析成event事件，消防事件查询用。
		List<FFHostEvent> eventList = this.parseFFHostEventFromData(ffHostState);
		if(eventList != null && eventList.size() > 0){
			this.resdataMapper.addFFHostStateEvent(eventList);
		}		
		// 4.检查对应告警. 告警恢复消息的判断... （缓存上一条数据，对比数据变化，决定告警恢复消息）
		this.checkFFHostStateAlarm(hostDev, ffHostState);
		logger.info("processFFHostStateData ok: data={}.", metedatajson);
	}
	
	private List<FFHostEvent> parseFFHostEventFromData(FFHostState data) throws Exception {
		if(data == null){
			return null;
		}
		List<FFHostEvent> ret = new ArrayList<FFHostEvent>();
		/**
		private byte runstate = 0; 		//	运行状态	Byte	0	N	1--正常运行；	0--测试状态；
		private byte firestate = 0; //	火警状态	Byte	0	N	1--火警；	0--无火警；
		private byte failstate = 0; //	故障状态	Byte	0	N	1--故障；	0--无故障；
		private byte maskstate = 0; //	屏蔽状态	Byte	0	N	1--屏蔽；	0--无屏蔽；
		private byte monistate = 0; //	监管状态	Byte	0	N	1--监管；	0--无监管；
		private byte openstate = 0; //	开启状态	Byte	0	N	1--开启；	0--关闭；
		private byte feedbackstate = 0; //	反馈状态	Byte	0	N	1--反馈；	0--无反馈；
		private byte delaystate = 0; 	//	延时状态	Byte	0	N	1--延时状态；	0--未延时；
		private byte mainpowerstate = 0; //	主电状态	Byte	0	N	1--主电故障；	0--主电正常；
		private byte bakpowerstate = 0;  //	备电状态	Byte	0	N	1--备电故障；	0--备电正常；
		private byte busstate = 0; 	//	总线状态	Byte	0	N	1--总线故障；	0--总线正常；
		private byte modestate = 0; //	模式状态	Byte	0	N	1--手动状态；	0--自动状态；
		private byte confchgstate = 0;  //	配置改变状态	Byte	0	N	1--配置改变；	0--无配置改变；
		private byte resetstate = 0; 	//	复位状态	Byte	0	N	1--复位；	0--正常；
		 */
		byte b = data.getRunstate();
		if(b == 1){
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_NORMAL);
			ret.add(event);
		} else {
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_TEST);
			ret.add(event);
		}
		b = data.getFirestate();
		if(b == 1){
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_FIRE);
			ret.add(event);
		}
		b = data.getFailstate();
		if(b == 1){
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_FAIL);
			ret.add(event);
		}
		b = data.getMaskstate();
		if(b == 1){
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_MASK);
			ret.add(event);
		}
		b = data.getMonistate();
		if(b == 1){
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_CTRL);
			ret.add(event);
		}
		b = data.getOpenstate();
		if(b == 1){
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_START);
			ret.add(event);
		}
		b = data.getFeedbackstate();
		if(b == 1){
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_FEEDBACK);
			ret.add(event);
		}
		b = data.getDelaystate();
		if(b == 1){
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_DELAY);
			ret.add(event);
		}
		b = data.getMainpowerstate();
		if(b == 1){
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_MPFAIL);
			ret.add(event);
		}
		b = data.getBakpowerstate();
		if(b == 1){
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_SPFAIL);
			ret.add(event);
		}
		b = data.getBusstate();
		if(b == 1){
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_BUSFAIL);
			ret.add(event);
		}
		b = data.getModestate();
		if(b == 1){
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_MANUAL);
			ret.add(event);
		}
		b = data.getConfchgstate();
		if(b == 1){
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_CONFCHG);
			ret.add(event);
		}
		b = data.getResetstate();
		if(b == 1){
			FFHostEvent event = FFHostEvent.fromFFHostState(data);
			event.setEventtype(FFHostEvent.EVENT_TP_RESET);
			ret.add(event);
		}
		return ret;
	}
	
	/**
	 * 消防部件状态数据上报处理
	 * 
	 * @param transdevEui
	 * @param metedatajson
	 * @throws Exception
	 */
	private void processFFHostPartStateData(FFResDevBase transDev, String metedatajson) throws Exception {
		// 1.转换json对象.
		String transDevAddr = transDev.getTransdevaddr();		
		FFHostPartState ffHostPartState = JsonUtils.readValue(metedatajson, FFHostPartState.class);
		FFResDevBase hostPartDev = this.cacheManager.getFFPartDevByAddr(transDevAddr, ffHostPartState.getSysaddr(), ffHostPartState.getPartaddr());
		if(hostPartDev == null){
			logger.error("hostPartDev not exists: transDevAddr={}, sysaddr={}, partaddr={}", transDevAddr, ffHostPartState.getSysaddr(), ffHostPartState.getPartaddr());
			return;
		}
		// 2.补充projectid和deveui等信息.
		ffHostPartState.setProjectid(hostPartDev.getProjectid());
		ffHostPartState.setDeveui(hostPartDev.getDeveui());
		Timestamp ts = ffHostPartState.getCollecttime();
		if(ts == null){
			ts = new Timestamp(System.currentTimeMillis());
			ffHostPartState.setCollecttime(ts);
		}
		// 3.持久化数据.
		// 3.1插入总体数据表（消防报表和统计分析用）；
		String partRemark = ffHostPartState.getRemark();
		if(partRemark != null){
			byte[] bs = partRemark.getBytes("UTF-8");
			partRemark = new String(bs, "UTF-8");
			ffHostPartState.setRemark(partRemark);
		}
		List<FFHostPartState> datas = new ArrayList<FFHostPartState>();
		datas.add(ffHostPartState);
		this.resdataMapper.addFFHostPartStateData(datas);
		// 3.2 解析成event事件，消防事件查询用。
		List<FFHostPartEvent> partEvents = this.parseFFPartEventFromData(ffHostPartState);
		if(partEvents != null && partEvents.size() > 0){
			this.resdataMapper.addFFHostPartStateEvent(partEvents);
		}
		// 4.检查对应告警. 告警恢复消息的判断... （缓存上一条数据，对比数据变化，决定告警恢复消息） 
		this.checkFFHostPartStateAlarm(hostPartDev, ffHostPartState);
		logger.info("processFFHostPartStateData ok: data={}.", metedatajson);
	}

	private List<FFHostPartEvent> parseFFPartEventFromData(FFHostPartState data) throws Exception {
		if(data == null){
			return null;
		}
		/**
		private byte runstate = 0;	//	运行状态	Byte	0	N	1--正常运行；	0--测试状态；
		private byte firestate = 0;	//	火警状态	Byte	0	N	1--火警；	0--无火警；
		private byte failstate = 0;	//	故障状态	Byte	0	N	1--故障；	0--无故障；
		private byte maskstate = 0;	//	屏蔽状态	Byte	0	N	1--屏蔽；	0--无屏蔽；
		private byte monistate = 0;	//	监管状态	Byte	0	N	1--监管；	0--无监管；
		private byte openstate = 0;	//	开启状态	Byte	0	N	1--开启；	0--关闭；
		private byte feedbackstate = 0;	//	反馈状态	Byte	0	N	1--反馈；	0--无反馈；
		private byte delaystate = 0;	//	延时状态	Byte	0	N	1--延时状态；	0--未延时；
		private byte powerstate = 0;	//	电源状态	Byte	0	N	1--电源故障；	0--电源正常；
		 */
		List<FFHostPartEvent> ret = new ArrayList<FFHostPartEvent>();
		byte b = data.getRunstate();
		if(b == 1){
			FFHostPartEvent event = FFHostPartEvent.fromFFHostPartState(data);
			event.setEventtype(FFHostPartEvent.EVENT_TP_NORMAL);
			ret.add(event);
		} else {
			FFHostPartEvent event = FFHostPartEvent.fromFFHostPartState(data);
			event.setEventtype(FFHostPartEvent.EVENT_TP_TEST);
			ret.add(event);
		}
		b = data.getFirestate();
		if(b == 1){
			FFHostPartEvent event = FFHostPartEvent.fromFFHostPartState(data);
			event.setEventtype(FFHostPartEvent.EVENT_TP_FIRE);
			ret.add(event);
		}
		b = data.getFailstate();
		if(b == 1){
			FFHostPartEvent event = FFHostPartEvent.fromFFHostPartState(data);
			event.setEventtype(FFHostPartEvent.EVENT_TP_FAIL);
			ret.add(event);
		}
		b = data.getMaskstate();
		if(b == 1){
			FFHostPartEvent event = FFHostPartEvent.fromFFHostPartState(data);
			event.setEventtype(FFHostPartEvent.EVENT_TP_MASK);
			ret.add(event);
		}
		b = data.getMonistate();
		if(b == 1){
			FFHostPartEvent event = FFHostPartEvent.fromFFHostPartState(data);
			event.setEventtype(FFHostPartEvent.EVENT_TP_CTRL);
			ret.add(event);
		}
		b = data.getOpenstate();
		if(b == 1){
			FFHostPartEvent event = FFHostPartEvent.fromFFHostPartState(data);
			event.setEventtype(FFHostPartEvent.EVENT_TP_START);
			ret.add(event);
		}
		b = data.getFeedbackstate();
		if(b == 1){
			FFHostPartEvent event = FFHostPartEvent.fromFFHostPartState(data);
			event.setEventtype(FFHostPartEvent.EVENT_TP_FEEDBACK);
			ret.add(event);
		}
		b = data.getDelaystate();
		if(b == 1){
			FFHostPartEvent event = FFHostPartEvent.fromFFHostPartState(data);
			event.setEventtype(FFHostPartEvent.EVENT_TP_DELAY);
			ret.add(event);
		}
		b = data.getPowerstate();
		if(b == 1){
			FFHostPartEvent event = FFHostPartEvent.fromFFHostPartState(data);
			event.setEventtype(FFHostPartEvent.EVENT_TP_POWFAIL);
			ret.add(event);
		}
		return ret;
	}
	
	/**
	 * 消防部件模拟量值数据上报处理
	 * 
	 * @param transdevEui
	 * @param metedatajson
	 * @throws Exception
	 */
	private void processFFHostPartFieldValueData(FFResDevBase transDev, String metedatajson) throws Exception {
		// 1.转换json对象.
		String transDevAddr = transDev.getTransdevaddr();		
		FFHostPartValue ffHostPartFieldVal = JsonUtils.readValue(metedatajson, FFHostPartValue.class);
		FFResDevBase hostPartDev = this.cacheManager.getFFPartDevByAddr(transDevAddr, ffHostPartFieldVal.getSysaddr(), ffHostPartFieldVal.getPartaddr());
		if(hostPartDev == null){
			logger.error("[2]hostPartDev not exists: transDevAddr={}, sysaddr={}, partaddr={}", transDevAddr, ffHostPartFieldVal.getSysaddr(), ffHostPartFieldVal.getPartaddr());
			return;
		}
		// 2.补充projectid和deveui等信息.
		ffHostPartFieldVal.setProjectid(hostPartDev.getProjectid());
		ffHostPartFieldVal.setDeveui(hostPartDev.getDeveui());
		Timestamp ts = ffHostPartFieldVal.getCollecttime();
		if(ts == null){
			ts = new Timestamp(System.currentTimeMillis());
			ffHostPartFieldVal.setCollecttime(ts);
		}
		// 3.持久化数据.
		List<FFHostPartValue> datas = new ArrayList<FFHostPartValue>();
		datas.add(ffHostPartFieldVal);
		this.resdataMapper.addFFHostPartValueData(datas);
		logger.info("processFFHostPartFieldValueData ok: data={}.", metedatajson);
	}

	/**
	 * 消防主机操作数据上报处理
	 * 
	 * @param transdevEui
	 * @param metedatajson
	 * @throws Exception
	 */
	private void processFFHostOpLogData(FFResDevBase transDev, String metedatajson) throws Exception {
		// 1.转换json对象.
		String transDevAddr = transDev.getTransdevaddr();		
		FFHostOpData ffHostOpData = JsonUtils.readValue(metedatajson, FFHostOpData.class);
		FFResDevBase hostDev = this.cacheManager.getFFHostDevByAddr(transDevAddr, ffHostOpData.getSysaddr());
		if(hostDev == null){
			logger.error("[2]FFHostDev not exists: transDevAddr={}, sysaddr={}", transDevAddr, ffHostOpData.getSysaddr());
			return;
		}
		// 2.补充projectid和deveui等信息.
		ffHostOpData.setProjectid(hostDev.getProjectid());
		ffHostOpData.setDeveui(hostDev.getDeveui());
		Timestamp ts = ffHostOpData.getCollecttime();
		if(ts == null){
			ts = new Timestamp(System.currentTimeMillis());
			ffHostOpData.setCollecttime(ts);
		}
		// 3.持久化数据.
		List<FFHostOpData> datas = new ArrayList<FFHostOpData>();
		datas.add(ffHostOpData);
		this.resdataMapper.addFFHostOpData(datas);
		logger.info("processFFHostOpLogData ok: data={}.", metedatajson);
	}
	
	/**
	 * 消防用户信息传输装置状态数据上报处理
	 * 
	 * @param transdevEui
	 * @param metedatajson
	 * @throws Exception
	 */
	private void processFFTransdevStateData(FFResDevBase transDev, String metedatajson) throws Exception {
		// 1.转换json对象.		
		FFTransDevState ffTransdevState = JsonUtils.readValue(metedatajson, FFTransDevState.class);
		// 2.补充projectid和deveui等信息.
		ffTransdevState.setProjectid(transDev.getProjectid());
		ffTransdevState.setDeveui(transDev.getDeveui());
		Timestamp ts = ffTransdevState.getCollecttime();
		if(ts == null){
			ts = new Timestamp(System.currentTimeMillis());
			ffTransdevState.setCollecttime(ts);
		}
		// 3.持久化数据.
		// 3.1插入总体数据表（消防报表和统计分析用）；
		List<FFTransDevState> datas = new ArrayList<FFTransDevState>();
		datas.add(ffTransdevState);
		this.resdataMapper.addFFTransDevStateData(datas);
		// 3.2解析成事件，消防event查询用...
		List<FFTransDevEvent> transDevEvents = this.parseFFTransdevEventFromData(ffTransdevState);
		if(transDevEvents != null && transDevEvents.size() > 0){
			this.resdataMapper.addFFTransDevStateEvent(transDevEvents);
		}				
		// 4.检查对应告警. 告警恢复消息的判断... （缓存上一条数据，对比数据变化，决定告警恢复消息）
		this.checkFFTransdevStateAlarm(transDev, ffTransdevState);
		logger.info("processFFTransdevStateData ok: data={}.", metedatajson);
	}
	
	// 解析传输装置状态数据，生成事件.
	private List<FFTransDevEvent> parseFFTransdevEventFromData(FFTransDevState data) throws Exception {
		if(data == null){
			return null;
		}
		/** 
		private byte runstate = 0; 	//		运行状态	Byte	0	N	1--正常监视状态；	0--测试状态；
		private byte firestate = 0; //		火警状态	Byte	0	N	1--火警；	0--无火警；
		private byte failstate = 0; //		故障状态	Byte	0	N	1--故障；	0--无故障；
		private byte mainpowerstate = 0; 	//		主电状态	Byte	0	N	1--主电故障；	0--主电正常；
		private byte bakpowerstate = 0; 	//		备电状态	Byte	0	N	1--备电故障；	0--备电正常；
		private byte connectstate = 0; 		//		连接状态（与上级监控平台链路）	Byte	0	N	1--连接故障；	0--连接正常；
		*/
		List<FFTransDevEvent> ret = new ArrayList<FFTransDevEvent>();
		byte b = data.getRunstate();
		if(b == 1){
			FFTransDevEvent event = FFTransDevEvent.fromFFTransDevState(data);
			event.setEventtype(FFTransDevEvent.EVENT_TP_NORMAL);
			ret.add(event);
		} else {
			FFTransDevEvent event = FFTransDevEvent.fromFFTransDevState(data);
			event.setEventtype(FFTransDevEvent.EVENT_TP_TEST);
			ret.add(event);
		}
		b = data.getFirestate();
		if(b == 1){
			FFTransDevEvent event = FFTransDevEvent.fromFFTransDevState(data);
			event.setEventtype(FFTransDevEvent.EVENT_TP_FIRE);
			ret.add(event);
		} 
		b = data.getFailstate();
		if(b == 1){
			FFTransDevEvent event = FFTransDevEvent.fromFFTransDevState(data);
			event.setEventtype(FFTransDevEvent.EVENT_TP_FAIL);
			ret.add(event);
		} 
		b = data.getMainpowerstate();
		if(b == 1){
			FFTransDevEvent event = FFTransDevEvent.fromFFTransDevState(data);
			event.setEventtype(FFTransDevEvent.EVENT_TP_MPFAIL);
			ret.add(event);
		} 
		b = data.getBakpowerstate();
		if(b == 1){
			FFTransDevEvent event = FFTransDevEvent.fromFFTransDevState(data);
			event.setEventtype(FFTransDevEvent.EVENT_TP_SPFAIL);
			ret.add(event);
		} 
		b = data.getConnectstate();
		if(b == 1){
			FFTransDevEvent event = FFTransDevEvent.fromFFTransDevState(data);
			event.setEventtype(FFTransDevEvent.EVENT_TP_CONNFAIL);
			ret.add(event);
		} 		
		return ret;
	}

	/**
	 * 消防用户信息传输装置状态数据上报处理
	 * 
	 * @param transdevEui
	 * @param metedatajson
	 * @throws Exception
	 */
	private void processFFTransdevOpLogData(FFResDevBase transDev, String metedatajson) throws Exception {
		// 1.转换json对象.		
		FFTransDevOpData ffTransdevOpData = JsonUtils.readValue(metedatajson, FFTransDevOpData.class);
		// 2.补充projectid和deveui等信息.
		ffTransdevOpData.setProjectid(transDev.getProjectid());
		ffTransdevOpData.setDeveui(transDev.getDeveui());
		Timestamp ts = ffTransdevOpData.getCollecttime();
		if(ts == null){
			ts = new Timestamp(System.currentTimeMillis());
			ffTransdevOpData.setCollecttime(ts);
		}
		// 3.持久化数据.
		List<FFTransDevOpData> datas = new ArrayList<FFTransDevOpData>();
		datas.add(ffTransdevOpData);
		this.resdataMapper.addFFTransDevOpData(datas);
		logger.info("processFFTransdevOpLogData ok: data={}.", metedatajson);
	}
	
	/**
	 * 检查消防主机对应告警. 告警恢复消息的判断... 
	 * （缓存上一条数据，对比数据变化，决定告警恢复消息）
	 * @param hostDev
	 * @param metedatajson
	 * @throws Exception
	 */
	private void checkFFHostStateAlarm(FFResDevBase hostDev, FFHostState ffHostState) throws Exception {
		// 1. 检查火警报警.
		try{
			AlarmData firealarm = this.checkFFHostFireAlarm(hostDev, ffHostState);
			if(firealarm != null){
				this.publishAlarmData(firealarm);
			}
		}catch(Exception e){
			logger.error("checkFFHostFireAlarm failed: "+ffHostState, e);
		}
		// 2. 检查故障告警
		try{
			AlarmData firealarm = this.checkFFHostFailureAlarm(hostDev, ffHostState);
			if(firealarm != null){
				this.publishAlarmData(firealarm);
			}
		}catch(Exception e){
			logger.error("checkFFHostFailureAlarm failed: "+ffHostState, e);
		}
		// 3. 主电状态告警
		try{
			AlarmData firealarm = this.checkFFHostMainPowerStateAlarm(hostDev, ffHostState);
			if(firealarm != null){
				this.publishAlarmData(firealarm);
			}
		}catch(Exception e){
			logger.error("checkFFHostMainPowerStateAlarm failed: "+ffHostState, e);
		}
		// 4. 备电状态告警
		try{
			AlarmData firealarm = this.checkFFHostBakPowerStateAlarm(hostDev, ffHostState);
			if(firealarm != null){
				this.publishAlarmData(firealarm);
			}
		}catch(Exception e){
			logger.error("checkFFHostBakPowerStateAlarm failed: "+ffHostState, e);
		}
		// 5. 总线状态告警
		try{
			AlarmData firealarm = this.checkFFHostBusStateAlarm(hostDev, ffHostState);
			if(firealarm != null){
				this.publishAlarmData(firealarm);
			}
		}catch(Exception e){
			logger.error("checkFFHostBusStateAlarm failed: "+ffHostState, e);
		}
		// 更新最近数据记录
		this.cacheManager.putFFLatestData(hostDev.getDeveui(), JsonUtils.toJson(ffHostState));
	}
	
	/**
	 * 检查消防部件对应告警. 告警恢复消息的判断... 
	 * （缓存上一条数据，对比数据变化，决定告警恢复消息）
	 * @param hostDev
	 * @param metedatajson
	 * @throws Exception
	 */
	private void checkFFHostPartStateAlarm(FFResDevBase hostPartDev, FFHostPartState ffHostPartState) throws Exception {
		// 1. 检查火警报警.
		try{
			AlarmData firealarm = this.checkFFHostpartFireAlarm(hostPartDev, ffHostPartState);
			if(firealarm != null){
				this.publishAlarmData(firealarm);
			}
		}catch(Exception e){
			logger.error("checkFFHostpartFireAlarm failed: "+ffHostPartState, e);
		}
		// 2. 检查故障告警
		try{
			AlarmData firealarm = this.checkFFHostpartFailureAlarm(hostPartDev, ffHostPartState);
			if(firealarm != null){
				this.publishAlarmData(firealarm);
			}
		}catch(Exception e){
			logger.error("checkFFHostpartFailureAlarm failed: "+ffHostPartState, e);
		}
		// 3. 电源故障告警
		try{
			AlarmData firealarm = this.checkFFHostpartPowerAlarm(hostPartDev, ffHostPartState);
			if(firealarm != null){
				this.publishAlarmData(firealarm);
			}
		}catch(Exception e){
			logger.error("checkFFHostpartPowerAlarm failed: "+ffHostPartState, e);
		}
		// 更新最近数据记录
		this.cacheManager.putFFLatestData(hostPartDev.getDeveui(), JsonUtils.toJson(ffHostPartState));
	}
	
	/**
	 * 检查用户信息传输装置对应告警. 告警恢复消息的判断... 
	 * 
	 * （缓存上一条数据，对比数据变化，决定告警恢复消息）
	 * @param hostDev
	 * @param metedatajson
	 * @throws Exception
	 */
	private void checkFFTransdevStateAlarm(FFResDevBase transDev, FFTransDevState ffTransdevState) throws Exception {
		// 1. 检查火警报警.
		try{
			AlarmData firealarm = this.checkFFTransdevFireAlarm(transDev, ffTransdevState);
			if(firealarm != null){
				this.publishAlarmData(firealarm);
			}
		}catch(Exception e){
			logger.error("checkFFTransdevFireAlarm failed: "+ffTransdevState, e);
		}
		// 2. 检查故障告警
		try{
			AlarmData firealarm = this.checkFFTransdevFailureAlarm(transDev, ffTransdevState);
			if(firealarm != null){
				this.publishAlarmData(firealarm);
			}
		}catch(Exception e){
			logger.error("checkFFTransdevFailureAlarm failed: "+ffTransdevState, e);
		}
		// 3. 主电状态告警
		try{
			AlarmData firealarm = this.checkFFTransdevMainPowerAlarm(transDev, ffTransdevState);
			if(firealarm != null){
				this.publishAlarmData(firealarm);
			}
		}catch(Exception e){
			logger.error("checkFFTransdevMainPowerAlarm failed: "+ffTransdevState, e);
		}
		// 4. 备电状态告警
		try{
			AlarmData firealarm = this.checkFFTransdevBakPowerAlarm(transDev, ffTransdevState);
			if(firealarm != null){
				this.publishAlarmData(firealarm);
			}
		}catch(Exception e){
			logger.error("checkFFTransdevBakPowerAlarm failed: "+ffTransdevState, e);
		}
		// 5. 总线状态告警
		try{
			AlarmData firealarm = this.checkFFTransdevConnAlarm(transDev, ffTransdevState);
			if(firealarm != null){
				this.publishAlarmData(firealarm);
			}
		}catch(Exception e){
			logger.error("checkFFTransdevConnAlarm failed: "+ffTransdevState, e);
		}
		// 更新最近数据记录
		this.cacheManager.putFFLatestData(transDev.getDeveui(), JsonUtils.toJson(ffTransdevState));
	}
	
	/**
	 * 检查消防控制主机的火警告警
	 * 
	 * @param hostDev
	 * @param ffHostState
	 * @return
	 * @throws Exception
	 */
	private AlarmData checkFFHostFireAlarm(FFResDevBase hostDev, FFHostState ffHostState) throws Exception {
		String hostDevEui = hostDev.getDeveui();
		byte alarmTypeFlag = AlarmData.TPFLAG_ALARM;
		byte fs = ffHostState.getFirestate();
		// 无告警。
		if(fs == 0) {
			// 检查是否需要做告警恢复消息.
			String jsonStr = this.cacheManager.getFFLatestData(hostDevEui);
			if(jsonStr != null){
				FFHostState oldData = JsonUtils.readValue(jsonStr, FFHostState.class);
				if(oldData != null && oldData.getFirestate() == fs){
					// 数据无变化，不需要产生告警恢复消息.
					return null;
				}
			}
			alarmTypeFlag = AlarmData.TPFLAG_CLEAR;
		}
		return this.buildAlarmData("1-1", "火警", alarmTypeFlag, hostDev, ffHostState.getCollecttime());
	}	
	
	/**
	 * 检查消防控制主机的故障告警
	 * failstate = 0; 故障状态	Byte	0	N	1--故障；	0--无故障；
	 * @param hostDev
	 * @param ffHostState
	 * @return
	 * @throws Exception
	 */
	private AlarmData checkFFHostFailureAlarm(FFResDevBase hostDev, FFHostState ffHostState) throws Exception {
		String hostDevEui = hostDev.getDeveui();
		byte alarmTypeFlag = AlarmData.TPFLAG_ALARM;
		byte fs = ffHostState.getFailstate();
		// 无告警。
		if(fs == 0) {
			// 检查是否需要做告警恢复消息.
			String jsonStr = this.cacheManager.getFFLatestData(hostDevEui);
			if(jsonStr != null){
				FFHostState oldData = JsonUtils.readValue(jsonStr, FFHostState.class);
				if(oldData != null && oldData.getFailstate() == fs){
					// 数据无变化，不需要产生告警恢复消息.
					return null;
				}
			}
			alarmTypeFlag = AlarmData.TPFLAG_CLEAR;
		}
		return this.buildAlarmData("1-2", "故障", alarmTypeFlag, hostDev, ffHostState.getCollecttime());
	}
	
	/**
	 * 检查消防控制主机的主电状态告警
	 * mainpowerstate = 0; 主电状态	Byte	0	N	1--主电故障；	0--主电正常；
	 * @param hostDev
	 * @param ffHostState
	 * @return
	 * @throws Exception
	 */
	private AlarmData checkFFHostMainPowerStateAlarm(FFResDevBase hostDev, FFHostState ffHostState) throws Exception {
		String hostDevEui = hostDev.getDeveui();
		byte alarmTypeFlag = AlarmData.TPFLAG_ALARM;
		byte fs = ffHostState.getMainpowerstate();
		// 无告警。
		if(fs == 0) {
			// 检查是否需要做告警恢复消息.
			String jsonStr = this.cacheManager.getFFLatestData(hostDevEui);
			if(jsonStr != null){
				FFHostState oldData = JsonUtils.readValue(jsonStr, FFHostState.class);
				if(oldData != null && oldData.getMainpowerstate() == fs){
					// 数据无变化，不需要产生告警恢复消息.
					return null;
				}
			}
			alarmTypeFlag = AlarmData.TPFLAG_CLEAR;
		}
		return this.buildAlarmData("1-3", "主电故障", alarmTypeFlag, hostDev, ffHostState.getCollecttime());
	}

	/**
	 * 检查消防控制主机的备电状态告警
	 * bakpowerstate = 0; 备电状态	Byte	0	N	1--主电故障；	0--主电正常；
	 * @param hostDev
	 * @param ffHostState
	 * @return
	 * @throws Exception
	 */
	private AlarmData checkFFHostBakPowerStateAlarm(FFResDevBase hostDev, FFHostState ffHostState) throws Exception {
		String hostDevEui = hostDev.getDeveui();
		byte alarmTypeFlag = AlarmData.TPFLAG_ALARM;
		byte fs = ffHostState.getBakpowerstate();
		// 无告警。
		if(fs == 0) {
			// 检查是否需要做告警恢复消息.
			String jsonStr = this.cacheManager.getFFLatestData(hostDevEui);
			if(jsonStr != null){
				FFHostState oldData = JsonUtils.readValue(jsonStr, FFHostState.class);
				if(oldData != null && oldData.getBakpowerstate() == fs){
					// 数据无变化，不需要产生告警恢复消息.
					return null;
				}
			}
			alarmTypeFlag = AlarmData.TPFLAG_CLEAR;
		}
		return this.buildAlarmData("1-4", "备电故障", alarmTypeFlag, hostDev, ffHostState.getCollecttime());
	}
	
	/**
	 * 检查消防控制主机的总线状态告警
	 * busstate = 0; 	总线状态	Byte	0	N	1--主电故障；	0--主电正常；
	 * @param hostDev
	 * @param ffHostState
	 * @return
	 * @throws Exception
	 */
	private AlarmData checkFFHostBusStateAlarm(FFResDevBase hostDev, FFHostState ffHostState) throws Exception {
		String hostDevEui = hostDev.getDeveui();
		byte alarmTypeFlag = AlarmData.TPFLAG_ALARM;
		byte fs = ffHostState.getBusstate();
		// 无告警。
		if(fs == 0) {
			// 检查是否需要做告警恢复消息.
			String jsonStr = this.cacheManager.getFFLatestData(hostDevEui);
			if(jsonStr != null){
				FFHostState oldData = JsonUtils.readValue(jsonStr, FFHostState.class);
				if(oldData != null && oldData.getBusstate() == fs){
					// 数据无变化，不需要产生告警恢复消息.
					return null;
				}
			}
			alarmTypeFlag = AlarmData.TPFLAG_CLEAR;
		}
		return this.buildAlarmData("1-5", "总线故障", alarmTypeFlag, hostDev, ffHostState.getCollecttime());
	}
	
	/**
	 * 检查消防设施部件的火警告警
	 * 
	 * @param hostDev
	 * @param ffHostState
	 * @return
	 * @throws Exception
	 */
	private AlarmData checkFFHostpartFireAlarm(FFResDevBase hostPartDev, FFHostPartState ffHostPartState) throws Exception {
		String hostPartDevEui = hostPartDev.getDeveui();
		byte alarmTypeFlag = AlarmData.TPFLAG_ALARM;
		byte fs = ffHostPartState.getFirestate();
		// 无告警。
		if(fs == 0) {
			// 检查是否需要做告警恢复消息.
			String jsonStr = this.cacheManager.getFFLatestData(hostPartDevEui);
			if(jsonStr != null){
				FFHostPartState oldData = JsonUtils.readValue(jsonStr, FFHostPartState.class);
				if(oldData != null && oldData.getFirestate() == fs){
					// 数据无变化，不需要产生告警恢复消息.
					return null;
				}
			}
			alarmTypeFlag = AlarmData.TPFLAG_CLEAR;
		}
		return this.buildAlarmData("1-1", "火警", alarmTypeFlag, hostPartDev, ffHostPartState.getCollecttime());
	}	
	
	/**
	 * 检查消防设施部件的故障告警
	 * failstate = 0; 故障状态	Byte	0	N	1--故障；	0--无故障；
	 * @param hostDev
	 * @param ffHostState
	 * @return
	 * @throws Exception
	 */
	private AlarmData checkFFHostpartFailureAlarm(FFResDevBase hostPartDev, FFHostPartState ffHostPartState) throws Exception {
		String hostPartDevEui = hostPartDev.getDeveui();
		byte alarmTypeFlag = AlarmData.TPFLAG_ALARM;
		byte fs = ffHostPartState.getFailstate();
		// 无告警。
		if(fs == 0) {
			// 检查是否需要做告警恢复消息.
			String jsonStr = this.cacheManager.getFFLatestData(hostPartDevEui);
			if(jsonStr != null){
				FFHostPartState oldData = JsonUtils.readValue(jsonStr, FFHostPartState.class);
				if(oldData != null && oldData.getFailstate() == fs){
					// 数据无变化，不需要产生告警恢复消息.
					return null;
				}
			}
			alarmTypeFlag = AlarmData.TPFLAG_CLEAR;
		}
		return this.buildAlarmData("1-2", "故障", alarmTypeFlag, hostPartDev, ffHostPartState.getCollecttime());
	}
	
	/**
	 * 检查消防部件设施的主电状态告警
	 * powerstate = 0; 主电状态	Byte	0	N	1--主电故障；	0--主电正常；
	 * @param hostDev
	 * @param ffHostState
	 * @return
	 * @throws Exception
	 */
	private AlarmData checkFFHostpartPowerAlarm(FFResDevBase hostPartDev, FFHostPartState ffHostPartState) throws Exception {
		String hostPartDevEui = hostPartDev.getDeveui();
		byte alarmTypeFlag = AlarmData.TPFLAG_ALARM;
		byte fs = ffHostPartState.getPowerstate();
		// 无告警。
		if(fs == 0) {
			// 检查是否需要做告警恢复消息.
			String jsonStr = this.cacheManager.getFFLatestData(hostPartDevEui);
			if(jsonStr != null){
				FFHostPartState oldData = JsonUtils.readValue(jsonStr, FFHostPartState.class);
				if(oldData != null && oldData.getPowerstate() == fs){
					// 数据无变化，不需要产生告警恢复消息.
					return null;
				}
			}
			alarmTypeFlag = AlarmData.TPFLAG_CLEAR;
		}
		return this.buildAlarmData("1-3", "电源故障", alarmTypeFlag, hostPartDev, ffHostPartState.getCollecttime());
	}
	
	/**
	 * 检查消防用户信息传输装置的火警告警
	 * 
	 * @param hostDev
	 * @param ffHostState
	 * @return
	 * @throws Exception
	 */
	private AlarmData checkFFTransdevFireAlarm(FFResDevBase transDev, FFTransDevState ffTransdevState) throws Exception {
		String transDevEui = transDev.getDeveui();
		byte alarmTypeFlag = AlarmData.TPFLAG_ALARM;
		byte fs = ffTransdevState.getFirestate();
		// 无告警。
		if(fs == 0) {
			// 检查是否需要做告警恢复消息.
			String jsonStr = this.cacheManager.getFFLatestData(transDevEui);
			if(jsonStr != null){
				FFTransDevState oldData = JsonUtils.readValue(jsonStr, FFTransDevState.class);
				if(oldData != null && oldData.getFirestate() == fs){
					// 数据无变化，不需要产生告警恢复消息.
					return null;
				}
			}
			alarmTypeFlag = AlarmData.TPFLAG_CLEAR;
		}
		return this.buildAlarmData("1-1", "火警", alarmTypeFlag, transDev, ffTransdevState.getCollecttime());
	}	
	
	/**
	 * 检查消防用户传输装置的故障告警
	 * failstate = 0; 故障状态	Byte	0	N	1--故障；	0--无故障；
	 * @param hostDev
	 * @param ffHostState
	 * @return
	 * @throws Exception
	 */
	private AlarmData checkFFTransdevFailureAlarm(FFResDevBase transDev, FFTransDevState ffTransdevState) throws Exception {
		String transDevEui = transDev.getDeveui();
		byte alarmTypeFlag = AlarmData.TPFLAG_ALARM;
		byte fs = ffTransdevState.getFailstate();
		// 无告警。
		if(fs == 0) {
			// 检查是否需要做告警恢复消息.
			String jsonStr = this.cacheManager.getFFLatestData(transDevEui);
			if(jsonStr != null){
				FFTransDevState oldData = JsonUtils.readValue(jsonStr, FFTransDevState.class);
				if(oldData != null && oldData.getFailstate() == fs){
					// 数据无变化，不需要产生告警恢复消息.
					return null;
				}
			}
			alarmTypeFlag = AlarmData.TPFLAG_CLEAR;
		}
		return this.buildAlarmData("1-2", "故障", alarmTypeFlag, transDev, ffTransdevState.getCollecttime());
	}
	
	/**
	 * 检查消防用户传输装置的主电状态告警
	 * mainpowerstate = 0; 主电状态	Byte	0	N	1--主电故障；	0--主电正常；
	 * @param hostDev
	 * @param ffHostState
	 * @return
	 * @throws Exception
	 */
	private AlarmData checkFFTransdevMainPowerAlarm(FFResDevBase transDev, FFTransDevState ffTransdevState) throws Exception {
		String transDevEui = transDev.getDeveui();
		byte alarmTypeFlag = AlarmData.TPFLAG_ALARM;
		byte fs = ffTransdevState.getMainpowerstate();
		// 无告警。
		if(fs == 0) {
			// 检查是否需要做告警恢复消息.
			String jsonStr = this.cacheManager.getFFLatestData(transDevEui);
			if(jsonStr != null){
				FFTransDevState oldData = JsonUtils.readValue(jsonStr, FFTransDevState.class);
				if(oldData != null && oldData.getMainpowerstate() == fs){
					// 数据无变化，不需要产生告警恢复消息.
					return null;
				}
			}
			alarmTypeFlag = AlarmData.TPFLAG_CLEAR;
		}
		return this.buildAlarmData("1-3", "主电故障", alarmTypeFlag, transDev, ffTransdevState.getCollecttime());
	}

	/**
	 * 检查消防用户传输装置的备电状态告警
	 * bakpowerstate = 0; 备电状态	Byte	0	N	1--主电故障；	0--主电正常；
	 * @param hostDev
	 * @param ffHostState
	 * @return
	 * @throws Exception
	 */
	private AlarmData checkFFTransdevBakPowerAlarm(FFResDevBase transDev, FFTransDevState ffTransdevState) throws Exception {
		String transDevEui = transDev.getDeveui();
		byte alarmTypeFlag = AlarmData.TPFLAG_ALARM;
		byte fs = ffTransdevState.getBakpowerstate();
		// 无告警。
		if(fs == 0) {
			// 检查是否需要做告警恢复消息.
			String jsonStr = this.cacheManager.getFFLatestData(transDevEui);
			if(jsonStr != null){
				FFTransDevState oldData = JsonUtils.readValue(jsonStr, FFTransDevState.class);
				if(oldData != null && oldData.getBakpowerstate() == fs){
					// 数据无变化，不需要产生告警恢复消息.
					return null;
				}
			}
			alarmTypeFlag = AlarmData.TPFLAG_CLEAR;
		}
		return this.buildAlarmData("1-4", "备电故障", alarmTypeFlag, transDev, ffTransdevState.getCollecttime());
	}
	
	/**
	 * 检查消防用户传输装置的连接状态告警
	 * connstate = 0; 	与云端连接状态	Byte	0	N	1--主电故障；	0--主电正常；
	 * @param hostDev
	 * @param ffHostState
	 * @return
	 * @throws Exception
	 */
	private AlarmData checkFFTransdevConnAlarm(FFResDevBase transDev, FFTransDevState ffTransdevState) throws Exception {
		String transDevEui = transDev.getDeveui();
		byte alarmTypeFlag = AlarmData.TPFLAG_ALARM;
		byte fs = ffTransdevState.getConnectstate();
		// 无告警。
		if(fs == 0) {
			// 检查是否需要做告警恢复消息.
			String jsonStr = this.cacheManager.getFFLatestData(transDevEui);
			if(jsonStr != null){
				FFTransDevState oldData = JsonUtils.readValue(jsonStr, FFTransDevState.class);
				if(oldData != null && oldData.getConnectstate() == fs){
					// 数据无变化，不需要产生告警恢复消息.
					return null;
				}
			}
			alarmTypeFlag = AlarmData.TPFLAG_CLEAR;
		}
		return this.buildAlarmData("1-5", "连接故障", alarmTypeFlag, transDev, ffTransdevState.getCollecttime());
	}
	
	// 构造告警.
	private AlarmData buildAlarmData(String alarmCode, String title, byte alarmTypeFlag, FFResDevBase hostDev, Timestamp rptTime){
		AlarmData alarm = new AlarmData();
		alarm.setAlarmcode(alarmCode);
		alarm.setTypeflag(alarmTypeFlag);
		alarm.setTitle(title);
		alarm.setDeveui(hostDev.getDeveui());
		alarm.setDevtype(hostDev.getDevtype());
		alarm.setProjectid(hostDev.getProjectid());
		alarm.setAlarmtime(rptTime);
		if(alarmTypeFlag == AlarmData.TPFLAG_CLEAR){
			alarm.setCleartime(rptTime);
		}
		alarm.setDescp(hostDev.getDevname()+title);
		alarm.setRemark(hostDev.getDevname()+title);
		// 设置dev名...
		alarm.setDevname(hostDev.getDevname());
		return alarm;
	}
	
	/**
	 * 告警发布
	 * 
	 * @param alarm
	 */
	private void publishAlarmData(AlarmData alarm){
		logger.debug("Publish alarm: "+alarm.toString());
		String alarmJson = JsonUtils.toJson(alarm);
		this.container.getAlarmPublisher().publishMessage(alarmJson);
		logger.info("[*^_^*]Publish alarm message ok: "+alarmJson);	
	}
	
}
